package com.rn.gypsophila.netty;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;

import java.nio.charset.Charset;
import java.time.LocalTime;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Description: 心跳处理器
 *
 * @author 然诺
 * @date 2021/04/20
 */
@Slf4j
public class HeartbeatHandler extends ChannelInboundHandlerAdapter {

    private AtomicInteger unRecPongTimes = new AtomicInteger(1);

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        String message = (String) msg;
        // 服务器端心跳回复
        if (message.contains("heartbeat")) {
            //如果服务器进行pong心跳回复，则清零失败心跳计数器
            unRecPongTimes = new AtomicInteger(1);
            log.info("client receive server pong msg :---->" + message);
        } else {
            ctx.fireChannelRead(msg);
        }
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            // 读超时
            if (event.state() == IdleState.READER_IDLE) {
               log.warn("===客户端===(READER_IDLE 读超时)");
            }
            // 写超时
            else if (event.state() == IdleState.WRITER_IDLE) {
                log.warn("===客户端===(WRITER_IDLE 写超时)");
                unRecPongTimes.getAndIncrement();
                // 服务端未进行pong心跳响应的次数小于3,则进行发送心跳，否则则断开连接
                if (unRecPongTimes.intValue() < 3) {
                    String ping = "heartbeat:ping\n";
                    //发送心跳，维持连接
                    ctx.channel().writeAndFlush(ping);
                    log.warn("客户端：发送心跳" + LocalTime.now());
                } else {
                    ctx.channel().close();
                }
            }
            // 总超时
            else if (event.state() == IdleState.ALL_IDLE) {
                log.warn("===客户端===(ALL_IDLE 总超时)");
            }
        }
        super.userEventTriggered(ctx, evt);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error("捕获的异常：" + cause);
        ctx.channel().close();
    }

    private ByteBuf getByteBuf(ChannelHandlerContext ctx) {
        // 1. 获取二进制抽象 ByteBuf
        ByteBuf buffer = ctx.alloc().buffer();
        String time = "heartbeat:ping";
        // 2. 准备数据，指定字符串的字符集为 utf-8
        byte[] bytes = time.getBytes(Charset.forName("utf-8"));
        // 3. 填充数据到 ByteBuf
        buffer.writeBytes(bytes);
        return buffer;
    }
}
